package kibahed.server.schnapsen;

import java.net.Socket;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Random;

import kibahed.interfaces.IServerClientConsumer;
import kibahed.interfaces.cards.Card;
import kibahed.interfaces.cards.CardFactory;
import kibahed.interfaces.cards.ECardValue;
import kibahed.interfaces.cards.EGame;
import kibahed.interfaces.cards.ESuite;

public class Schnapsserver implements IServerClientConsumer {

	Schnapser spieler1;
	Schnapser spieler2;
	Card karteSpieler1;
	Card karteSpieler2;

	private boolean farbStichZwang = false;
	private Card ausgepsielteKarte = null;

	private boolean spieler1restart;
	private boolean spieler2restart;

	private Map<Socket, Schnapser> player = new HashMap<Socket, Schnapser>();

	private String name;

	private ESuite adut;
	private Card offeneKarte;
	private List<Card> stapel;

	public Schnapsserver(String name) {
		this.name = name;
		spieler1restart = false;
		spieler2restart = false;
	}

	@Override
	public void doSpecificActions(Socket socket, String msg) {
		Schnapser p = player.get(socket);

		if (p != null) {
			StringBuffer buff = new StringBuffer();
			if ((karteSpieler1 == null && karteSpieler2 == null && p == spieler1)
					|| (karteSpieler1 != null && karteSpieler2 == null && p == spieler2)) {
				if (msg.startsWith("schnapsen/spiele/")) {
					String[] splitMsg = msg.split("/");
					try {
						ESuite suite = ESuite.valueOf(splitMsg[2]);
						ECardValue cardValue = ECardValue.valueOf(splitMsg[3]);
						Card card = CardFactory.getCard(EGame.SCHNAPSEN, suite,
								cardValue);
						boolean cardAllowed = checkSpiel(p, card);
						if (cardAllowed) {
							p.sendMessageToClient("schnapsen/spiel/accepted/"
									+ card.getTag("/"));
							if (p == spieler1) {
								karteSpieler1 = card;
								spieler2.sendMessageToClient("schnapsen/gegner/spiel/"
										+ card.getTag("/"));
								ausgepsielteKarte = card;
								spieleAus(spieler2);
							} else {
								karteSpieler2 = card;
								spieler1.sendMessageToClient("schnapsen/gegner/spiel/"
										+ card.getTag("/"));
								if (karteSpieler1 != null
										&& karteSpieler2 != null) {
									checkStich();
								}
							}

						} else {
							p.sendMessageToClient("schnapsen/spiel/notAccepted/"
									+ card.getTag("/"));
						}

					} catch (Exception e) {
						buff.append("false input");
						p.sendMessageToClient(buff.toString());
						e.printStackTrace();
					}
				}
			}

			if (msg.startsWith("schnapsen/tauscheAus/")) {
				String[] splitMsg = msg.split("/");
				try {
					ESuite suite = ESuite.valueOf(splitMsg[2]);
					ECardValue cardValue = ECardValue.valueOf(splitMsg[3]);
					Card card = CardFactory.getCard(EGame.SCHNAPSEN, suite,
							cardValue);
					boolean switchAllowed = checkAustausch(p, card);
					if (switchAllowed) {
						p.getHandkarten().remove(card);
						p.sendMessageToClient("schnapsen/tauscheAus/accepted/"
								+ card.getTag("/"));
						p.sendMessageToClient("schnapsen/card/"
								+ offeneKarte.getTag("/"));
						p.getHandkarten().remove(card);
						p.getHandkarten().add(offeneKarte);
						spieler2.sendMessageToClient("schnapsen/gegner/ausgetauscht/"
								+ card.getTag("/"));
						offeneKarte = card;
					} else {
						p.sendMessageToClient("schnapsen/tauscheAus/notAccepted/"
								+ card.getTag("/"));
					}
					spieleAus(p);

				} catch (Exception e) {
					buff.append("false input");
					p.sendMessageToClient(buff.toString());
					e.printStackTrace();
				}

			}

			if (msg.startsWith("schnapsen/paar/")) {

				String[] splitMsg = msg.split("/");
				try {
					ESuite suite = ESuite.valueOf(splitMsg[2]);
					ECardValue cardValue = ECardValue.valueOf(splitMsg[3]);
					Card card = CardFactory.getCard(EGame.SCHNAPSEN, suite,
							cardValue);
					if (checkPaar(p, card) && checkSpiel(p, card)) {
						int value = 0;
						if (card.getSuite() == adut) {
							value = 40;
							p.sagePaarAn(value);
							p.sendMessageToClient("schnapsen/paar/accepted/40/"
									+ card.getTag("/"));
						} else {
							value = 20;
							p.sagePaarAn(value);
							p.sendMessageToClient("schnapsen/paar/accepted/20/"
									+ card.getTag("/"));
						}

						p.sendMessageToClient("schnapsen/spiel/accepted/"
								+ card.getTag("/"));
						spieler2.sendMessageToClient("schnapsen/gegner/paar/"
								+ value + "/" + card.getTag("/"));

						karteSpieler1 = card;
						spieler2.sendMessageToClient("schnapsen/gegner/spiel/"
								+ card.getTag("/"));
						spieleAus(spieler2);

					} else {
						p.sendMessageToClient("schnapsen/paar/notAccepted");
					}

				} catch (Exception e) {
					buff.append("false input");
					p.sendMessageToClient(buff.toString());
					e.printStackTrace();
				}

			}

			if (msg.startsWith("schnapsen/zudrehen")) {
				if (ausgepsielteKarte == null && p == spieler1) {
					farbStichZwang = true;
					spieler1.sendMessageToClient("schnapsen/zudrehen/accepted");
					spieler2.sendMessageToClient("schnapsen/gegner/zugedreht");
				} else {
					spieler1.sendMessageToClient("schnapsen/zudrehen/notAccepted");
				}
				spieleAus(p);
			}

			if (msg.startsWith("schnapsen/genug")) {

			}

			if (msg.startsWith("schnapsen/neueRunde")) {
				if (p == spieler1) {
					spieler1restart = true;
				} else if (p == spieler2) {
					spieler2restart = true;
				}
				if (spieler1restart && spieler2restart) {
					neueRunde();
				}
			}

			if (msg.startsWith("schnapsen/neuesBummerl")) {
				if (spieler1 != null && spieler2 != null) {
					startBummerl();
				}
			}
		}
	}

	private void startBummerl() {
		spieler1.neuesBummerl();
		spieler2.neuesBummerl();
		spieler1.sendMessageToClient("schnapsen/bummerlGestartet");
		spieler2.sendMessageToClient("schnapsen/bummerlGestartet");
		starteSpiel();
	}

	private void neueRunde() {
		spieler1.neueRunde();
		spieler2.neueRunde();
		spieler1restart = false;
		spieler2restart = false;
		ausgepsielteKarte = null;
		farbStichZwang = false;
		starteSpiel();
	}

	private boolean checkPaar(Schnapser player, Card card) {

		if (player == spieler1 && karteSpieler1 == null) {
			if (card.getCardValue() == ECardValue.DAME) {
				Card koenig = CardFactory.getCard(EGame.SCHNAPSEN,
						card.getSuite(), ECardValue.KOENIG);
				return player.getHandkarten().contains(koenig);
			}

			if (card.getCardValue() == ECardValue.KOENIG) {
				Card dame = CardFactory.getCard(EGame.SCHNAPSEN,
						card.getSuite(), ECardValue.DAME);
				return player.getHandkarten().contains(dame);
			}
		}

		return false;
	}

	private boolean checkAustausch(Schnapser p, Card card) {
		if (ausgepsielteKarte == null && p == spieler1 && !stapel.isEmpty()) {
			if (card.getSuite().equals(adut)
					&& card.getCardValue() == ECardValue.BUB) {
				return true;
			}
		}
		return false;
	}

	private boolean checkSpiel(Schnapser player, Card karte) {
		if ((player == spieler1 && karteSpieler1 == null)
				|| (player == spieler2 && karteSpieler2 == null)) {
			return getAllowedCards(player).contains(karte);
		} else {
			return false;
		}
	}

	private void checkStich() {

		Card c1 = karteSpieler1;
		Card c2 = karteSpieler2;
		spieler1.getHandkarten().remove(karteSpieler1);
		spieler2.getHandkarten().remove(karteSpieler2);

		boolean spieler1Gewonnen = false;

		if (karteSpieler1.getSuite() == adut
				&& karteSpieler2.getSuite() != adut) {
			spieler1Gewonnen = true;
		} else if (karteSpieler2.getSuite() == adut
				&& karteSpieler1.getSuite() != adut) {
			spieler1Gewonnen = false;
		} else {
			if ((karteSpieler1.getSuite() == karteSpieler2.getSuite())
					&& (karteSpieler2.getValue() > karteSpieler1.getValue())) {
				spieler1Gewonnen = false;
			} else {
				spieler1Gewonnen = true;
			}
		}

		if (spieler1Gewonnen) {
			spieler1.sendMessageToClient("schnapsen/stichGewonnen/"
					+ karteSpieler1.getTag("/") + ";"
					+ karteSpieler2.getTag("/"));
			spieler2.sendMessageToClient("schnapsen/stichVerloren");
			spieler1.addStich(c1);
			spieler1.addStich(c2);
		} else {
			spieler2.sendMessageToClient("schnapsen/stichGewonnen/"
					+ karteSpieler1.getTag("/") + ";"
					+ karteSpieler2.getTag("/"));
			spieler1.sendMessageToClient("schnapsen/stichVerloren");
			spieler2.addStich(c1);
			spieler2.addStich(c2);
			switchPlayers();
		}

		karteSpieler1 = null;
		karteSpieler2 = null;
		ausgepsielteKarte = null;

		if (!stapel.isEmpty() && !farbStichZwang) {
			abheben();
		} 

		if (spieler1.getScore() > 65) {
			if (spieler2.getScore() == 0) {
				spieler1.sendMessageToClient("schnapsen/gewonnen/3");
				spieler2.sendMessageToClient("schnapsen/verloren/3");
				spieler1.decreasePunkte(3);
			}
			if (spieler2.getScore() < 33 && spieler2.getScore() > 0) {
				spieler1.sendMessageToClient("schnapsen/gewonnen/2");
				spieler2.sendMessageToClient("schnapsen/verloren/2");
				spieler1.decreasePunkte(2);
			}
			if (spieler2.getScore() > 32) {
				spieler1.sendMessageToClient("schnapsen/gewonnen/1");
				spieler2.sendMessageToClient("schnapsen/verloren/1");
				spieler1.decreasePunkte(1);
			}
			if (spieler1.getPunkte() > 0) {
				neueRunde();
			} else {
				spieler1.sendMessageToClient("schnapsen/bummerlGewonnen");
				spieler2.sendMessageToClient("schnapsen/bummerlVerloren");
				spieler1.sendMessageToClient("schnapsen/bummerlBeendet");
				spieler2.sendMessageToClient("schnapsen/bummerlBeendet");
			}
		} else {
			spieleAus(spieler1);
		}
	}

	private void abheben() {
		Card c1 = stapel.remove(0);
		Card c2;
		if (stapel.isEmpty()) {
			c2 = offeneKarte;
			farbStichZwang = true;
		} else {
			c2 = stapel.remove(0);
		}
		if(stapel.isEmpty()) {
			spieler1.sendMessageToClient("schnapsen/stapelLeer");
			spieler2.sendMessageToClient("schnapsen/stapelLeer");
		}
		
		spieler1.addHandkarte(c1);
		spieler2.addHandkarte(c2);
		spieler1.sendMessageToClient("schnapsen/card/" + c1.getTag("/"));
		spieler2.sendMessageToClient("schnapsen/card/" + c2.getTag("/"));
	}

	@Override
	public boolean isAlive() {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public void setSocket(Socket socket) {
		Schnapser schnapser = new Schnapser(socket);
		player.put(socket, schnapser);

		if (player.keySet().size() == 1) {
			spieler1 = schnapser;
		}

		if (player.keySet().size() == 2) {
			spieler2 = schnapser;
		}
	}

	private void starteSpiel() {

		spieler1.sendMessageToClient("schnapsen/start");
		spieler2.sendMessageToClient("schnapsen/start");

		Random r = new Random();
		int i = r.nextInt();
		if (i == 1) {
			switchPlayers();
		}
		stapel = CardFactory.getCardDeck(EGame.SCHNAPSEN);
		Collections.shuffle(stapel);
		for (int j = 1; j < 4; j++) {
			spieler1.addHandkarte(stapel.remove(0));
		}
		for (int j = 1; j < 4; j++) {
			spieler2.addHandkarte(stapel.remove(0));
		}
		offeneKarte = stapel.remove(0);
		adut = offeneKarte.getSuite();
		for (int j = 1; j < 3; j++) {
			spieler1.addHandkarte(stapel.remove(0));
		}
		for (int j = 1; j < 3; j++) {
			spieler2.addHandkarte(stapel.remove(0));
		}
		teileAus();
		spieleAus(spieler1);
	}

	private List<Card> getAllowedCards(Schnapser player) {
		List<Card> allowedCards = new LinkedList<Card>();
		if (ausgepsielteKarte != null && farbStichZwang) {
			boolean hasFarbe = false;
			boolean isHigher = false;
			for (Card c : player.getHandkarten()) {
				if (c.getSuite().equals(ausgepsielteKarte.getSuite())) {
					allowedCards.add(c);
					hasFarbe = true;
					if (c.getValue() > ausgepsielteKarte.getValue()) {
						isHigher = true;
					}
				}
			}
			if (isHigher) {
				List<Card> toRemove = new LinkedList<Card>();
				for (Card c : allowedCards) {
					if (c.getValue() < ausgepsielteKarte.getValue()) {
						toRemove.add(c);
					}
				}
				allowedCards.removeAll(toRemove);
			}
			boolean hasAdut = false;
			if (!hasFarbe) {
				for (Card c : player.getHandkarten()) {
					if (c.getSuite().equals(adut)) {
						allowedCards.add(c);
						hasAdut = true;
					}
				}
			}
			if (!hasFarbe && !hasAdut) {
				allowedCards.addAll(player.getHandkarten());
			}
		} else {
			allowedCards.addAll(player.getHandkarten());
		}
		return allowedCards;
	}

	private void sendAllowedCards(Schnapser player) {
		StringBuffer buff = new StringBuffer();
		buff.append("schnapsen/allowedCards");
		List<Card> allowedCards = getAllowedCards(player);
		for (int i = 0; i < allowedCards.size(); i++) {
			buff.append("/" + allowedCards.get(i).getTag("/"));
			if (i < allowedCards.size() - 1) {
				buff.append(";");
			}
		}
		player.sendMessageToClient(buff.toString());
	}

	private void teileAus() {
		for (Card c : spieler1.getHandkarten()) {
			spieler1.sendMessageToClient("schnapsen/card/" + c.getTag("/"));
		}
		for (Card c : spieler2.getHandkarten()) {
			spieler2.sendMessageToClient("schnapsen/card/" + c.getTag("/"));
		}
		spieler1.sendMessageToClient("schnapsen/adut/"
				+ offeneKarte.getTag("/"));
		spieler2.sendMessageToClient("schnapsen/adut/"
				+ offeneKarte.getTag("/"));
	}

	private void spieleAus(Schnapser aktuellerSpieler) {
		aktuellerSpieler.sendMessageToClient("schnapsen/spieleAus");
		sendAllowedCards(aktuellerSpieler);
	}

	private void switchPlayers() {
		Schnapser s = new Schnapser();
		s = spieler1;
		spieler1 = spieler2;
		spieler2 = s;
	}
}
